package com.xbai.ext;

import com.xbai.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author jxbai
 * @desc 扩展原理
 * BeanPostProcessor：bean 后置处理器，bean 创建对象初始化前后进行拦截工作的
 * BeanFactoryPostProcessor：beanFactory 的后置处理器；
 *      在 BeanFactory 标准初始化之后调用；所有的 bean 定义已经保存加载到 beanFactory，但是 bean 的实例还未创建
 *
 * 执行时机:
 *  1、ioc 容器创建对象
 *  2、invokeBeanFactoryPostProcessors(beanFactory);执行 BeanFactoryPostProcessor
 *      如何找到所有的 BeanFactoryPostProcessor 并执行他们的方法；
 *          1、直接在 BeanFactory 中找到所有类型是 BeanFactoryPostProcessor 的组件，并执行他们的方法
 *          2、在初始化创建其他组件前面执行
 *
 * BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
 *      postProcessBeanDefinitionRegistry();
 *      在所有 bean 定义信息将要被加载，bean 实例还未被创建的时候
 *      优先于 BeanFactoryPostProcessor 执行，利用  BeanDefinitionRegistryPostProcessor 给容器中再额外添加一些组件
 * 原理
 *  1、ioc 容器创建对象
 *  2、invokeBeanFactoryPostProcessors(beanFactory);执行 BeanDefinitionRegistryPostProcessor
 *  3、从容器中获取到所有的 BeanDefinitionRegistryPostProcessor 组件
 *      1、依次触发所有的 BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry() 方法
 *      2、再来触发 BeanFactoryPostProcessor.postProcessBeanFactory() 方法
 *  4、再来从容器中找到 BeanFactoryPostProcessor 组件，然后依次触发 postProcessBeanFactory() 方法
 *
 *
 * ApplicationListener：监听容器中发布的事件。事件驱动模型开发；
 *      public interface ApplicationListener<E extends ApplicationEvent> extends EventListener
 *      监听 ApplicationEvent 及其下面的子事件
 *
 *  监听自己写的事件。步骤：
 *      1、写一个监听器（ApplicationListener 实现类）来监听某个事件（ApplicationEvent 及其下面的子事件）
 *          @EventListener;
 *          原理：使用 EventListenerMethodProcessor 处理器来解析方法上的 @EventListener
 *      2、把监听器加入到容器
 *      3、只要容器中有相关事件的发布，我们就能监听到这个事件
 *          ContextRefreshedEvent：容器刷新完成（所有 bean 都完全创建）会发布这个事件；
 *          ContextClosedEvent：关闭容器会发布这个事件
 *      4、发布一个事件：applicationContext.publishEvent();
 *
 * 原理：
 *  ContextRefreshedEvent：
 *      1、容器创建对象：refresh();
 *      2、finishRefresh();容器刷新完成会发布 ContextRefreshedEvent 事件
 *      3、publishEvent(new ContextRefreshedEvent(this));
 *  IOCExtTest$1[source=我发布的事件]：
 *  ContextClosedEvent：容器关闭会发布 ContextClosedEvent 事件
 *
 *      事件发布流程
 *          1、getApplicationEventMulticaster()：获取事件的多波器（派发器）
 *          2、multicastEvent()：派发事件
 *          3、获取到所有的 ApplicationListener
 *              for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
 *              1、如果有 Executor 可以支持使用 Executor 进行异步派发
 *              2、invokeListener(listener, event); 否则，同步的方式直接执行 listener 方法
 *              拿到 listener 回调 onApplicationEvent 方法
 *
 *  事件的多波器（派发器）：
 *      1、容器创建对象：refresh();
 *      2、initApplicationEventMulticaster();初始化 ApplicationEventMulticaster
 *          1、先去容器中找有没有 id="applicationEventMulticaster" 的组件
 *          2、如果没有，this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
 *          并且加入到容器中，我们就可以在其他组件要派发事件，自动注入这个 applicationEventMulticaster
 *
 *  getApplicationListeners(event, type))：容器中有哪些监听器
 *      1、容器创建对象：refresh();
 *      2、registerListeners();
 *          从容器中拿到所有的监听器，把他们注册到 ApplicationEventMulticaster
 *          将 listener 注册到 ApplicationEventMulticaster 中
 *          String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
 *
 *  SmartInitializingSingleton：
 *      1、容器创建对象：refresh();
 *      2、finishBeanFactoryInitialization(beanFactory); 初始化剩下的单实例 bean；
 *          1、先创建所有的单实例 bean；getBean(beanName);
 *          2、获取所有创建好的单实例 bean；判断是否是 SmartInitializingSingleton 类型的
 *              如果是，就调用 afterSingletonsInstantiated() 方法
 * @date 2021/5/17
 */
@Configuration
@ComponentScan("com.xbai.ext")
public class ExtConfig {

    @Bean
    public Car car() {
        return new Car();
    }
}
